<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>光照</title>
    <style>
        body {
            margin: 0;
        }
        canvas {
            width: 100vw;
            height: 100vh;
            display: block;
        }
    </style>
</head>
<body onload="main()">
    <canvas id="c"></canvas>
</body>
<script type="text/javascript" src="lib/webgl-utils.js"></script>
<script type="text/javascript" src="lib/m4.js"></script>
<script type="text/javascript" src="lib/primitives.js"></script>
<script type="notjs" id="vertex-shader-3d">
    attribute vec4 a_position;
    //uniform vec4 u_baseColor;
    attribute vec4 a_baseColor;
    varying vec4 v_baseColor;
    uniform mat4 u_mvpMatrix;
    attribute vec4 a_normal;
    uniform vec3 u_lightColor;
    uniform vec3 u_lightDirection;//需要normalize
    uniform vec3 u_ambientLightColor;//环境光颜色
    uniform mat4 u_normalMatrix;//运动物体的法线重计算：物体的线性运动矩阵的逆矩阵
    void main(){
        gl_Position = u_mvpMatrix * a_position;
        //gl_Position = a_position;
        gl_PointSize = 5.0;

        //漫反射 光照计算
        vec3 normal = normalize(vec3(u_normalMatrix * a_normal));
        float nDot = max(dot(u_lightDirection, normal),0.0);//光线和法线夹角
        vec3 diffuse = u_lightColor * a_baseColor.rgb * nDot;//直射光漫反射
        vec3 ambient = vec3(u_ambientLightColor * a_baseColor.rgb);//环境光漫反射
        v_baseColor = vec4(diffuse + ambient, a_baseColor.a);
    }
</script>
<script type="notjs" id="fragement-shader-3d">
    precision mediump float;
    varying vec4 v_baseColor;
    void main() {
        gl_FragColor = v_baseColor;
    }
</script>
<script type="text/javascript">

    function main(){
        let modelRotator = [15, -17, 0];
        let lightColor = [1.0, 1.0, 1.0];//直射白光颜色
        let lightDirection = [0, 0.5, 1];//方向
        let ambientLightColor = [0.1, 0.1, 0.2];//环境光颜色

        var canvas = document.getElementById("c");
        var gl = canvas.getContext("webgl");

        setupEvent();

        var program = webglUtils.createProgramFromScripts(gl, ["vertex-shader-3d", "fragement-shader-3d"]);
        var a_position = gl.getAttribLocation(program, "a_position");
        //var u_baseColor = gl.getUniformLocation(program, "u_baseColor");
        var a_baseColor = gl.getAttribLocation(program, "a_baseColor");
        var u_mvpMatrix = gl.getUniformLocation(program, "u_mvpMatrix");
        var a_normal = gl.getAttribLocation(program, "a_normal");
        var u_lightColor = gl.getUniformLocation(program, "u_lightColor");
        var u_lightDirection = gl.getUniformLocation(program, "u_lightDirection");
        var u_ambientLightColor = gl.getUniformLocation(program, "u_ambientLightColor");
        var u_normalMatrix = gl.getUniformLocation(program, "u_normalMatrix");

        var positionBuffer = gl.createBuffer();
        var n = setGeometry();
        // var n = setGeometry_Lines();

        var colorBuffer = gl.createBuffer();
        setColor();

        var normalBuffer = gl.createBuffer();
        setNormal();

        render();

        setupAnimatoin();

        //渲染
        function render(){
            webglUtils.resizeCanvasToDisplaySize(gl.canvas);
            gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

            gl.clearColor(0.0, 0.0, 0.0, 1.0);
            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
            //遮挡面剔除
            gl.enable(gl.CULL_FACE);
            gl.enable(gl.DEPTH_TEST);

            gl.useProgram(program);

            //mvp
            var near = -400;
            var far = 400;
            var projectMatrix = m4.orthographic(-gl.canvas.clientWidth, gl.canvas.clientWidth, -gl.canvas.clientHeight, gl.canvas.clientHeight, near, far);//p
            var cameraPos = [0, 0, 100];
            var target = [0.0, 0.0, 0.0];
            var up = [0, 1, 0];
            var cameraMatrix = m4.lookAt(cameraPos, target, up);
            var viewMatrix = m4.inverse(cameraMatrix);//v
            var modelMatrix = m4.identity();//m
            modelMatrix = m4.xRotate(modelMatrix, radians(modelRotator[0]));
            modelMatrix = m4.yRotate(modelMatrix, radians(modelRotator[1]));
            modelMatrix = m4.zRotate(modelMatrix, radians(modelRotator[2]));
            modelMatrix = m4.scale(modelMatrix, 5, 5, 5);
            var mvpMatrix = m4.multiply(projectMatrix, viewMatrix);
            mvpMatrix = m4.multiply(mvpMatrix, modelMatrix);
            gl.uniformMatrix4fv(u_mvpMatrix, false, mvpMatrix);
            var normalMatrix = m4.inverse(modelMatrix);
            m4.transpose(normalMatrix, normalMatrix);
            gl.uniformMatrix4fv(u_normalMatrix, false, normalMatrix);

            gl.enableVertexAttribArray(a_position);
            gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
            gl.vertexAttribPointer(a_position, 3, gl.FLOAT, false, 0, 0);

            gl.enableVertexAttribArray(a_baseColor);
            gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
            gl.vertexAttribPointer(a_baseColor, 3, gl.UNSIGNED_BYTE, true, 0, 0);
            //gl.uniform4fv(u_baseColor, [0.2, 1, 0.2, 1]);
            gl.uniform3fv(u_lightColor, lightColor);
            gl.uniform3fv(u_lightDirection, m4.normalize(lightDirection));
            gl.uniform3fv(u_ambientLightColor, m4.normalize(ambientLightColor));
            console.log('归一化平行光线的方向' + m4.normalize(lightDirection))

            gl.enableVertexAttribArray(a_normal);
            gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
            gl.vertexAttribPointer(a_normal, 3, gl.FLOAT, true, 0, 0);


            gl.drawArrays(gl.TRIANGLES, 0, n);
            //gl.drawElements(gl.TRIANGLES, indicesLen, gl.UNSIGNED_BYTE, 0);
        }

        //几何体
        function setGeometry() {
            // Create a cube
            //    v6----- v5
            //   /|      /|
            //  v1------v0|
            //  | |     | |
            //  | |v7---|-|v4
            //  |/      |/
            //  v2------v3
            // 0, 1, 2,   0, 2, 3,    // 前
            //     0, 3, 4,   0, 4, 5,    // 右
            //     0, 5, 6,   0, 6, 1,    // 上
            //     1, 6, 7,   1, 7, 2,    // 左
            //     7, 4, 3,   7, 3, 2,    // 下
            //     4, 7, 6,   4, 6, 5     // 后

            var positions = [
                // v0-v1-v2-v3 front
                50, 50, 50,//0
                -50,50,50,//1
                -50,-50,50,//2
                50,50,50,//0
                -50,-50,50,//2
                50,-50,50,//3

                // v0-v3-v4-v5 right
                50, 50, 50,//0
                50,-50,50,//3
                50, 50, -50,//4
                50, 50, -50,//0
                50,-50,50,//4
                50,-50,-50,//5

                // v0-v5-v6-v1 up
                50, 50, 50,//0
                50,50,-50,//5
                -50,50,-50,//6
                50, 50, 50,//0
                -50,50,-50,//6
                -50,50,50,//1

                // v1-v6-v7-v2 left
                -50, 50, 50,//1
                -50, 50, -50,//6
                -50,-50, -50,//7
                -50, 50, 50,//1
                -50,-50, -50,//7
                -50,-50,50,//2

                // v7-v4-v3-v2 bottom
                -50,-50,-50,//7
                50,-50,-50,//4
                50,-50,50,//3
                -50,-50,-50,//7
                50,-50,50,//3
                -50,-50,50,//2

                // v4-v7-v6-v5 back
                50,-50,-50,//4
                -50,-50,-50,//7
                -50, 50, -50,//6
                50,-50,-50,//4
                -50, 50, -50,//6
                50,50,-50,//5
            ];
            gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
            return 6 * 6;
        }

        function setGeometry_Lines() {
            var positions = [
                100, 100, 0,
                100,100,-400,
                -100,-100,-400,
                -100,-100,0
            ];

            gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
            return 4;
        }

        function setColor(){
            var colors = [
                // front
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,


                // right
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,

                // top
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,

                //left
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,

                //bottom
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,

                //back
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,
                95, 158, 160,
            ];

            gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
            gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array(colors), gl.STATIC_DRAW);
        }

        function setNormal(){
            var normals = [
                // v0-v1-v2-v3 front
                0, 0, 1,//0
                0, 0, 1,//1
                0, 0, 1,//2
                0, 0, 1,//0
                0, 0, 1,//2
                0, 0, 1,//3

                // v0-v3-v4-v5 right
                1, 0, 0,//0
                1, 0, 0,//5
                1, 0, 0,//6
                1, 0, 0,//0
                1, 0, 0,//6
                1, 0, 0,//1

                // v0-v5-v6-v1 up
                0, 1, 0,//0
                0, 1, 0,//3
                0, 1, 0,//4
                0, 1, 0,//0
                0, 1, 0,//4
                0, 1, 0,//5

                // v1-v6-v7-v2 left
                -1, 0, 0,//7
                -1, 0, 0,//4
                -1, 0, 0,//3
                -1, 0, 0,//7
                -1, 0, 0,//3
                -1, 0, 0,//2

                // v7-v4-v3-v2 bottom
                0, -1, 0,//1
                0, -1, 0,//6
                0, -1, 0,//7
                0, -1, 0,//1
                0, -1, 0,//7
                0, -1, 0,//2

                // v4-v7-v6-v5 back
                0, 0, -1,//4
                0, 0, -1,//7
                0, 0, -1,//6
                0, 0, -1,//4
                0, 0, -1,//6
                0, 0, -1,//5
            ];
            gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normals), gl.STATIC_DRAW);
        }

        //立方体
        function setCube(){
            var cubeVerticeInfo = primitives.createCubeVertices(10);
            gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
            gl.bufferData(gl.ARRAY_BUFFER, cubeVerticeInfo.position, gl.STATIC_DRAW);

            var indicesBuffer = gl.createBuffer();
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesBuffer);
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, cubeVerticeInfo.indices, gl.STATIC_DRAW);
            return cubeVerticeInfo.indices.length;
        }

        //事件绑定
        function setupEvent(){
            document.onkeydown = function (event) {
                switch (event.keyCode) {
                    case 65:
                        yAxis(0.1);
                        break;
                    case 68:
                        yAxis(-0.1);
                        break;
                    case 87:
                        xAxis(-0.1);
                        break;
                    case 83:
                        xAxis(0.1);
                        break;
                    default:return;
                }
                return true;
            };
        }


        function xAxis(value){
            var newAngle = modelRotator[0] + angleAxis * value;
            modelRotator[0] = newAngle % 360;
            console.log(modelRotator)
            render();
        }

        function yAxis(value){
            var newAngle = modelRotator[1] + angleAxis * value;
            modelRotator[1] = newAngle % 360;
            render();
        }

        function setupAnimatoin(){
            //requestAnimationFrame(rotateModel);
        }

        var lastTime = Date.now();
        var angleAxis = 45;//每秒45度
        function rotateModel(){
            var now = Date.now();
            var during = now - lastTime;
            lastTime = now;

            var xRotator = modelRotator[0] + (angleAxis * during) / 1000.0;
            var yRotator = modelRotator[1] + (angleAxis * during) / 1000.0;

            modelRotator[0] = xRotator % 360.0;
            modelRotator[1] = yRotator % 360.0;
            render();
            requestAnimationFrame(rotateModel);
        }
    }

    //角度转弧度
    function radians(degree){
        return degree * Math.PI / 180;
    }

    //弧度转角度
    function degree(radians){
        return radians * 180 / Math.PI;
    }
</script>
</html>























